package com.rupertjones.globalcron.server.web.security;

import com.rupertjones.globalcron.common.domain.AuditLog;
import com.rupertjones.globalcron.common.domain.AuditLogType;
import com.rupertjones.globalcron.common.domain.Role;
import com.rupertjones.globalcron.common.domain.User;
import com.rupertjones.globalcron.server.dao.AuditLogDAO;
import com.rupertjones.globalcron.server.dao.UserDAO;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;

import static java.lang.String.format;

/**
 * <p>&copy Rupert Jones 2011,2012</p>
 *
 * @author rup
 */
@Service
@Transactional
public class PersistedAuthenticationProvider implements AuthenticationProvider {

    private static final Logger LOG = Logger.getLogger(AuthenticationProvider.class);

    @Autowired
    private UserDAO userDAO;

    @Autowired
    private AuditLogDAO auditLogDAO;

    @Override
    public Authentication authenticate(Authentication authentication) {
        String username = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();
        User user = userDAO.login(username, password);

        if (user == null) {
            LOG.warn("Could not authenticate user with username: " + username);
            throw new GlobalCronAuthenticationException("Authentication failed");
        }

        Collection<GrantedAuthority> auth = new ArrayList<GrantedAuthority>();
        for (Role role : user.getRoles()) {
            auth.add(new Authority(role.getName()));
        }
        user.registerLogin();
        userDAO.upsert(user);

        AuditLog auditLog = new AuditLog();
        auditLog.setMessage("User logged in");
        auditLog.setUser(user.getUsername());
        auditLog.setType(AuditLogType.LOGIN);
        auditLogDAO.upsert(auditLog);

        LOG.info(format("User %s successfully logged in with roles [%s]", username, auth));
        return new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), auth);
    }

    @Override
    public boolean supports(Class<? extends Object> aClass) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
    }
}
